/**
 * @file    jbd_modbus.c
 * @brief   JBD-MODBUS协议
 * @author  Liuwei
 * @version 1.0.1
 * @date    2023-12-12
 * 
 * @copyright Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD
 * 
 * @par 修改日志:
 * <table>
 * <tr><th>Date       <th>Version   <th>Author   <th>Description
 * <tr><td>2023-12-13 <td>1.0.1     <td>Liuwei   <td>首次创建
 * </table>
 */

/* includes ------------------------------------------------------------------*/
#include "jbd_modbus.h"
#include "modbus_app.h"
#include "if_di.h"
#include "cfg_prj.h"
#include "dev_rtc.h"
#include "pc_jbd.h"
#include "var_mng.h"
#include "param_mng.h"
#include "sample.h"
#include "parallel.h"
#include "if_rtc.h"
#include "boot_param.h"
#include "If_do.h"
/* macro/define --------------------------------------------------------------*/

/* typedef -------------------------------------------------------------------*/
#define INPUT_REG_ST         (0x1000)
#define INPUT_REG_SIZE       (0x50)
#define INPUT2_REG_ST        (0x1050)
#define INPUT2_REG_SIZE      (0x20)
#define HOLD1_REG_ST         (0x1800)
#define HOLD1_REG_SIZE       (0x80)
#define HOLD2_REG_ST         (0x1A00)
#define HOLD2_REG_SIZE       (0x20)

#define CMD_READ_IN_REG      (0x04)
#define CMD_READ_HOLD_REG    (0x03)
#define CMD_WRITE_HOLD_REG   (0x10)

/* local functions -----------------------------------------------------------*/
static void jbd_modbus_read_input_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len);
static void jbd_modbus_read_input2_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len);
static void jbd_modbus_read_hold1_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len);
static void jbd_modbus_read_hold2_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len);
static void jbd_modbus_write_hold1_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len);
static void jbd_modbus_write_hold2_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len);
static uint8_t jbd_modbus_update_input_buf(md_data_type md_data_msg);
static uint8_t jbd_modbus_update_input2_buf(md_data_type md_data_msg);
static void jbd_modbus_update_hold1_buf(void);
static void jbd_modbus_update_hold2_buf(void);
static uint32_t get_salve_prp_msg(uint8_t slave_addr);
static uint32_t get_salve_alm_msg(uint8_t slave_addr);
static void jbd_modbus_write_reply_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len);
static uint16_t get_slave_sys_status(uint8_t slave_addr);
static uint16_t get_master_sys_status(void);
static uint16_t get_self_sys_status(void);
/* static variables ----------------------------------------------------------*/
static uint16_t input_reg_buf[INPUT_REG_SIZE] = {0};
static uint16_t input2_reg_buf[INPUT_REG_SIZE] = {0};
static uint16_t hold1_reg_buf[HOLD1_REG_SIZE] = {0};
static uint16_t hold2_reg_buf[HOLD2_REG_SIZE] = {0};
static const uint16_t sys_para_map_list[] = 
{
	PAR_ID_COV_ALM_VAL ,PAR_ID_COV_ALM_RCV, PAR_ID_COV_ALM_DLY ,
	PAR_ID_COV_PRP_VAL ,PAR_ID_COV_PRP_RCV, PAR_ID_COV_PRP_DLY ,  

	PAR_ID_CUV_ALM_VAL ,PAR_ID_CUV_ALM_RCV, PAR_ID_CUV_ALM_DLY , 
	PAR_ID_CUV_PRP_VAL ,PAR_ID_CUV_PRP_RCV, PAR_ID_CUV_PRP_DLY ,

	PAR_ID_BOV_ALM_VAL ,PAR_ID_BOV_ALM_RCV, PAR_ID_BOV_ALM_DLY ,
	PAR_ID_BOV_PRP_VAL ,PAR_ID_BOV_PRP_RCV, PAR_ID_BOV_PRP_DLY ,

	PAR_ID_BUV_ALM_VAL ,PAR_ID_BUV_ALM_RCV, PAR_ID_BUV_ALM_DLY ,
	PAR_ID_BUV_PRP_VAL ,PAR_ID_BUV_PRP_RCV, PAR_ID_BUV_PRP_DLY ,

	PAR_ID_OCC_ALM_VAL  ,PAR_ID_OCC_ALM_RCV  ,PAR_ID_OCC_ALM_DLY  ,
	PAR_ID_OCC_PRP_VAL  ,PAR_ID_OCC_PRP_DLY  ,PAR_ID_OCC_RCV_DLY  ,
	PAR_ID_OCC_LOCK_TIMES ,
	PAR_ID_OCC2_PRP_VAL ,PAR_ID_OCC2_PRP_DLY  ,PAR_ID_OCC2_RCV_DLY,
	
	PAR_ID_OCD1_ALM_VAL  ,PAR_ID_OCD1_ALM_RCV  ,PAR_ID_OCD1_ALM_DLY,
	PAR_ID_OCD1_PRP_VAL  ,PAR_ID_OCD1_PRP_DLY  ,PAR_ID_OCD1_RCV_DLY,
	PAR_ID_OCD1_LOCK_TIMES,
	PAR_ID_OCD2_PRP_VAL ,PAR_ID_OCD2_PRP_DLY,PAR_ID_OCD2_RCV_DLY  ,

	PAR_ID_OTC_ALM_VAL  ,PAR_ID_OTC_ALM_RCV  ,PAR_ID_OTC_ALM_DLY  ,
	PAR_ID_OTC_PRP_VAL  ,PAR_ID_OTC_PRP_RCV  ,PAR_ID_OTC_PRP_DLY  ,

	PAR_ID_UTC_ALM_VAL  ,PAR_ID_UTC_ALM_RCV  ,PAR_ID_UTC_ALM_DLY  ,
	PAR_ID_UTC_PRP_VAL  ,PAR_ID_UTC_PRP_RCV  ,PAR_ID_UTC_PRP_DLY  ,

	PAR_ID_OTD_ALM_VAL  ,PAR_ID_OTD_ALM_RCV  ,PAR_ID_OTD_ALM_DLY  ,
	PAR_ID_OTD_PRP_VAL  ,PAR_ID_OTD_PRP_RCV  ,PAR_ID_OTD_PRP_DLY  ,
	
	PAR_ID_UTD_ALM_VAL  ,PAR_ID_UTD_ALM_RCV  ,PAR_ID_UTD_ALM_DLY  ,
	PAR_ID_UTD_PRP_VAL  ,PAR_ID_UTD_PRP_RCV  ,PAR_ID_UTD_PRP_DLY  ,
	
	PAR_ID_OTM_ALM_VAL  ,PAR_ID_OTM_ALM_RCV  ,PAR_ID_OTM_ALM_DLY  ,
	PAR_ID_OTM_PRP_VAL  ,PAR_ID_OTM_PRP_RCV  ,PAR_ID_OTM_PRP_DLY  ,
	
	PAR_ID_OTE_ALM_VAL  ,PAR_ID_OTE_ALM_RCV  ,PAR_ID_OTE_ALM_DLY  ,
	PAR_ID_OTE_PRP_VAL  ,PAR_ID_OTE_PRP_RCV  ,PAR_ID_OTE_PRP_DLY  ,
	
	PAR_ID_UTE_ALM_VAL  ,PAR_ID_UTE_ALM_RCV  ,PAR_ID_UTE_ALM_DLY  ,
	PAR_ID_UTE_PRP_VAL  ,PAR_ID_UTE_PRP_RCV  ,PAR_ID_UTE_PRP_DLY  ,

	PAR_ID_TDIFF_ALM_VAL ,PAR_ID_TDIFF_ALM_RCV ,PAR_ID_TDIFF_ALM_DLY ,
	PAR_ID_TDIFF_PRP_VAL ,PAR_ID_TDIFF_PRP_RCV ,PAR_ID_TDIFF_PRP_DLY ,

	PAR_ID_VDIFF_ALM_VAL ,PAR_ID_VDIFF_ALM_RCV ,PAR_ID_VDIFF_ALM_DLY ,
	PAR_ID_VDIFF_PRP_VAL ,PAR_ID_VDIFF_PRP_RCV ,PAR_ID_VDIFF_PRP_DLY ,

	PAR_ID_SOCL_ALM_VAL  ,PAR_ID_SOCL_ALM_RCV  ,PAR_ID_SOCL_ALM_DLY  ,
	PAR_ID_SOCL_PRP_VAL  ,PAR_ID_SOCL_PRP_RCV  ,PAR_ID_SOCL_PRP_DLY  ,
};

#define SYS_PRP_PARA_NUM    (sizeof(sys_para_map_list)/sizeof(sys_para_map_list[0]))
/* global variables ----------------------------------------------------------*/

/** ------------------------------------------------------------------------- *
  *                             Global function
 ** ------------------------------------------------------------------------- */
uint8_t jbd_modbus_analysis(uint8_t *rx_buf , uint16_t rx_len ,uint8_t *tx_buf , uint16_t *tx_len)
{
    md_data_type recv_md_data = {0};
	uint8_t res = 0;
    if(TRUE == modbus_rtu_analysis(rx_buf , rx_len , &recv_md_data))
    {
		if((recv_md_data.addr >= 0x10) && 
			((PARALLEL_MASTER_ADDR == var_get_data(VAR_ID_SELF_ADDR) || (recv_md_data.addr <= 0x11))))
		{
			if(CMD_READ_IN_REG == recv_md_data.cmd_code)
			{
				if((recv_md_data.reg_addr >= INPUT_REG_ST)
					&& (recv_md_data.reg_addr + recv_md_data.data_len <= INPUT_REG_ST + INPUT_REG_SIZE))
				{
					res = jbd_modbus_update_input_buf(recv_md_data);
					jbd_modbus_read_input_reg(recv_md_data , tx_buf , tx_len);
					return res;
				}
				else if((recv_md_data.reg_addr >= INPUT2_REG_ST)
					&& (recv_md_data.reg_addr + recv_md_data.data_len <= INPUT2_REG_ST + INPUT2_REG_SIZE))
				{
					res = jbd_modbus_update_input2_buf(recv_md_data);
					jbd_modbus_read_input2_reg(recv_md_data , tx_buf , tx_len);
					return res;
				}
				else
				{
					
				}
			}
			else if(CMD_READ_HOLD_REG == recv_md_data.cmd_code)
			{
				if((recv_md_data.reg_addr >= HOLD1_REG_ST)
					&& (recv_md_data.reg_addr + recv_md_data.data_len <= HOLD1_REG_ST + HOLD1_REG_SIZE))
				{
					jbd_modbus_update_hold1_buf();
					jbd_modbus_read_hold1_reg(recv_md_data , tx_buf , tx_len);
					return TRUE;
				}
				else if((recv_md_data.reg_addr >= HOLD2_REG_ST)
					&& (recv_md_data.reg_addr + recv_md_data.data_len <= HOLD2_REG_ST + HOLD2_REG_SIZE))
				{
					jbd_modbus_update_hold2_buf();
					jbd_modbus_read_hold2_reg(recv_md_data , tx_buf , tx_len);
					return TRUE;
				}
				else
				{
					return FALSE;
				}
			}
			else if(CMD_WRITE_HOLD_REG == recv_md_data.cmd_code)
			{
				if((recv_md_data.reg_addr >= HOLD1_REG_ST)
					&& (recv_md_data.reg_addr + recv_md_data.data_len <= HOLD1_REG_ST + HOLD1_REG_SIZE))
				{
					jbd_modbus_write_hold1_reg(recv_md_data , tx_buf , tx_len);
					jbd_modbus_write_reply_reg(recv_md_data , tx_buf , tx_len);
					return TRUE;
				}
				else if((recv_md_data.reg_addr >= HOLD2_REG_ST)
					&& (recv_md_data.reg_addr + recv_md_data.data_len <= HOLD2_REG_ST + HOLD2_REG_SIZE))
				{
					jbd_modbus_write_hold2_reg(recv_md_data , tx_buf , tx_len);
					jbd_modbus_write_reply_reg(recv_md_data , tx_buf , tx_len);
					return TRUE;
				}
				else
				{
					return FALSE;
				}
			}
			else
			{
				return FALSE;
			}
		}
		else
		{
			return FALSE;
		}
    }
    return FALSE;
}

/** ------------------------------------------------------------------------- *
  *                              Local function
 ** ------------------------------------------------------------------------- */
static void jbd_modbus_read_input_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len)
{
    uint16_t data_len = 0;
    uint16_t crc_code = 0;
    uint8_t i = 0;
    uint8_t *p_tx = tx_buf;
    uint16_t start_addr = 0;

    *p_tx ++ = md_data_msg.addr;
    *p_tx ++ = md_data_msg.cmd_code;
    data_len = md_data_msg.data_len * 2; 
    *p_tx ++ = data_len; 
   	
    start_addr = md_data_msg.reg_addr - INPUT_REG_ST;
    for(i = 0;(i < md_data_msg.data_len) && (i < INPUT_REG_SIZE); ++ i)
    {
        *p_tx ++ = input_reg_buf[i + start_addr] >> 8;
        *p_tx ++  = input_reg_buf[i + start_addr] & 0xff;
    }
	
    crc_code = modbus_calc_crc(tx_buf , data_len + 3);

    *p_tx ++ = crc_code;
    *p_tx ++ = crc_code >> 8;

    *tx_len = (data_len + 5);
} 

static void jbd_modbus_read_input2_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len)
{
    uint16_t data_len = 0;
    uint16_t crc_code = 0;
    uint8_t i = 0;
    uint8_t *p_tx = tx_buf;
    uint16_t start_addr = 0;

    *p_tx ++ = md_data_msg.addr;
    *p_tx ++ = md_data_msg.cmd_code;
    data_len = md_data_msg.data_len * 2; 
    *p_tx ++ = data_len; 
   	
    start_addr = md_data_msg.reg_addr - INPUT2_REG_ST;
    for(i = 0;(i < md_data_msg.data_len) && (i < INPUT2_REG_SIZE); ++ i)
    {
        *p_tx ++ = input2_reg_buf[i + start_addr] >> 8;
        *p_tx ++  = input2_reg_buf[i + start_addr] & 0xff;
    }
	
    crc_code = modbus_calc_crc(tx_buf , data_len + 3);

    *p_tx ++ = crc_code;
    *p_tx ++ = crc_code >> 8;

    *tx_len = (data_len + 5);
} 

static uint8_t jbd_modbus_update_input_buf(md_data_type md_data_msg)
{
	uint8_t i = 0;
	uint8_t addr = 0;
	int16_t curr = 0;
	uint8_t max_sn = 0;
	uint8_t min_sn = 0xff;
	uint16_t max_val = 0;
	uint16_t min_val = 0xffff;
	uint32_t u32_val = 0;
	uint8_t soh = 0;
	addr = md_data_msg.addr - 0x10;
	
	if(PARALLEL_MASTER_ADDR == var_get_data(VAR_ID_SELF_ADDR))
	{
		/* 统计信息 */
		if(0 == addr)
		{
			input_reg_buf[0] = master_data_reg.avg_batt_volt;
			curr = master_data_reg.total_bus_curr;
			input_reg_buf[1] = curr;
			input_reg_buf[2] = master_data_reg.avg_soc;
			input_reg_buf[3] = master_data_reg.avg_soh;
			input_reg_buf[4] = master_data_reg.max_volt_sn;
			input_reg_buf[5] = master_data_reg.avg_max_volt;
			input_reg_buf[6] = master_data_reg.min_volt_sn;
			input_reg_buf[7] = master_data_reg.avg_min_volt;
			input_reg_buf[8] = master_data_reg.max_temp_sn;
			input_reg_buf[9] = master_data_reg.max_temp_val - 2231;
			input_reg_buf[10] = master_data_reg.min_temp_sn;
			input_reg_buf[11] = master_data_reg.min_temp_val - 2231;
			input_reg_buf[12] = master_data_reg.slave_data[0].env_temp - 2231;
			input_reg_buf[13] = master_data_reg.slave_data[0].mos_temp - 2231;
			input_reg_buf[14] = get_master_sys_status();
			input_reg_buf[15] = master_data_reg.total_full_cap;
			input_reg_buf[16] = master_data_reg.total_real_cap;
			input_reg_buf[17] = master_data_reg.total_prp_msg.prp_word >> 16;
			input_reg_buf[18] = master_data_reg.total_prp_msg.prp_word & 0xffff;
			input_reg_buf[19] = 0;
			input_reg_buf[20] = 0;
			for(i = 0;i < 10; ++ i)
			{
				input_reg_buf[21 + i] = 0;
			}
			input_reg_buf[31] = var_get_data(VAR_ID_TP_SOP_CV);
			input_reg_buf[32] = var_get_data(VAR_ID_TP_SOP_CC);
			input_reg_buf[33] = var_get_data(VAR_ID_TP_SOP_DV);
			input_reg_buf[34] = var_get_data(VAR_ID_TP_SOP_DC);
			if(master_data_reg.total_bus_curr == 0)
			{
				input_reg_buf[35] = 0xffff;
				input_reg_buf[36] = 0xffff;
			}
			else
			{
				if(master_data_reg.total_bus_curr > 0)
				{
					input_reg_buf[35] = (master_data_reg.total_full_cap - master_data_reg.total_real_cap) * 60 / master_data_reg.total_bus_curr;
					input_reg_buf[36] = 0xffff;
				}
				else
				{
					input_reg_buf[35] = 0xffff;
					input_reg_buf[36] = -master_data_reg.total_real_cap * 60 / master_data_reg.total_bus_curr;
				}
			}
			
			input_reg_buf[37] = master_data_reg.parallel_num;
			input_reg_buf[38] = master_data_reg.com_err_state;
			input_reg_buf[39] = master_data_reg.avg_cycle;
			input_reg_buf[40] = 0;
			input_reg_buf[41] = param_get_data(PAR_ID_CB_CELL_NUM);
			for(i = 0;i < 16; ++ i)
			{
				input_reg_buf[42 + i] = master_data_reg.avg_cell_buf[i];
			}
			input_reg_buf[58] = param_get_data(PAR_ID_CB_TEMP_NUM);	
			for(i = 0;i < CFG_TEMP_NUM; ++ i)
			{
				input_reg_buf[59 + i] = master_data_reg.avg_temp_buf[i]-2231;
			}
			
			return TRUE;
		}
		else
		{
			addr = addr - 1;
			if((master_data_reg.com_err_state & (1 << addr)) && (addr < CFG_PARALLEL_NUM))
			{
				input_reg_buf[0] = master_data_reg.avg_batt_volt;
				curr = (master_data_reg.slave_data[addr].curr_h16 << 16) + master_data_reg.slave_data[addr].curr_l16;
				input_reg_buf[1] = curr;
				input_reg_buf[2] = master_data_reg.slave_data[addr].soc;
				input_reg_buf[3] = master_data_reg.slave_data[addr].soh;
				
				max_sn = 1;
				min_sn = 1;
				max_val = 0;
				min_val = 0xffff;
				for( i = 0;i < (master_data_reg.slave_data[addr].cell_num) &&(i < SLAVE_CELL_NUM); ++ i)
				{
					if(master_data_reg.slave_data[addr].cell_volt_buf[i] >= max_val)
					{
						max_val = master_data_reg.slave_data[addr].cell_volt_buf[i];
						max_sn = i + 1;
					}
					if(master_data_reg.slave_data[addr].cell_volt_buf[i] < min_val)
					{
						min_val = master_data_reg.slave_data[addr].cell_volt_buf[i];
						min_sn = i + 1;
					}
				}
				input_reg_buf[4] = max_sn;
				input_reg_buf[5] = max_val;
				input_reg_buf[6] = min_sn;
				input_reg_buf[7] = min_val;
				
				max_sn = 1;
				min_sn = 1;
				max_val = 0;
				min_val = 0xffff;
				for( i = 0;i < (master_data_reg.slave_data[addr].temp_num) && (i < SLAVE_TEMP_NUM); ++ i)
				{
					if(master_data_reg.slave_data[addr].cell_temp_buf[i] >= max_val)
					{
						max_val = master_data_reg.slave_data[addr].cell_temp_buf[i];
						max_sn = i + 1;
					}
					if(master_data_reg.slave_data[addr].cell_temp_buf[i] < min_val)
					{
						min_val = master_data_reg.slave_data[addr].cell_temp_buf[i];
						min_sn = i + 1;
					}
				}
				input_reg_buf[8] = max_sn;
				input_reg_buf[9] = max_val - 2231;
				input_reg_buf[10] = min_sn;
				input_reg_buf[11] = min_val - 2231;
				input_reg_buf[12] = master_data_reg.slave_data[addr].env_temp - 2231;
				input_reg_buf[13] = master_data_reg.slave_data[addr].mos_temp - 2231;
				input_reg_buf[14] = get_slave_sys_status(addr);
				input_reg_buf[15] = master_data_reg.slave_data[addr].full_cap;
				input_reg_buf[16] = master_data_reg.slave_data[addr].real_cap;
				u32_val = get_salve_prp_msg(addr);
				input_reg_buf[17] = u32_val >> 16;
				input_reg_buf[18] = u32_val & 0xffff;
				u32_val = get_salve_alm_msg(addr);
				input_reg_buf[19] = u32_val >> 16;
				input_reg_buf[20] = u32_val & 0xffff;
				for(i = 0;i < 10; ++ i)
				{
					input_reg_buf[21 + i] = master_data_reg.slave_data[addr].sn_code[i];
				}
				input_reg_buf[31] = var_get_data(VAR_ID_TP_SOP_CV);
				input_reg_buf[32] = master_data_reg.slave_data[addr].sop_cc;
				input_reg_buf[33] = var_get_data(VAR_ID_TP_SOP_DV);
				input_reg_buf[34] = master_data_reg.slave_data[addr].sop_dc;
				for(i = 0;i < 6; ++ i)
				{
					input_reg_buf[35 + i] = 0;
				}
				input_reg_buf[39] = master_data_reg.slave_data[addr].cycle;
				input_reg_buf[40] = 0;//var_get_data(VAR_ID_SYS_STEP);
				input_reg_buf[41] = master_data_reg.slave_data[addr].cell_num;
				for(i = 0;i < 16; ++ i)
				{
					input_reg_buf[42 + i] = master_data_reg.slave_data[addr].cell_volt_buf[i];
				}
				input_reg_buf[58] = param_get_data(PAR_ID_CB_TEMP_NUM);	
				for(i = 0;i < CFG_TEMP_NUM; ++ i)
				{
					input_reg_buf[59 + i] = master_data_reg.slave_data[addr].cell_temp_buf[i] - 2231;
				}
				
				return TRUE;
			}
			else
			{
				return FALSE;
			}
		}
	}
	else
	{
		if((addr == 1)||(addr == 0))
		{
			input_reg_buf[0] = var_get_data(VAR_ID_BATT_VOLT);
			curr = var_get_data(VAR_ID_BUS_CURR) - 30000;
			input_reg_buf[1] = curr;
			input_reg_buf[2] = var_get_data(VAR_ID_DISP_SOC) * 0.01;
			soh = param_get_data(PAR_ID_SOH);
	        if(soh > 100)
		       soh = 100;
			input_reg_buf[3] = soh;
			input_reg_buf[4] = var_get_data(VAR_ID_MAX_CELL_SN) &0x0f;
			input_reg_buf[5] = var_get_data(VAR_ID_MAX_CELL_VOLT);
			input_reg_buf[6] = var_get_data(VAR_ID_MIN_CELL_SN) & 0x0f;
			input_reg_buf[7] = var_get_data(VAR_ID_MIN_CELL_VOLT);
			input_reg_buf[8] = var_get_data(VAR_ID_MAX_TEMP_SN) & 0x0f;
			input_reg_buf[9] = var_get_data(VAR_ID_MAX_TEMP_VAL);
			input_reg_buf[10] = var_get_data(VAR_ID_MIN_TEMP_SN) & 0x0f;
			input_reg_buf[11] = var_get_data(VAR_ID_MAX_TEMP_VAL);
			input_reg_buf[12] = var_get_data(VAR_ID_ENV_TEMP);
			input_reg_buf[13] = var_get_data(VAR_ID_MOS_TEMP);
			input_reg_buf[14] = get_self_sys_status();
			input_reg_buf[15] = param_get_data(PAR_ID_FULL_CAP);
			input_reg_buf[16] = var_get_data(VAR_ID_DISP_RCAP);
			input_reg_buf[17] = diag_get_all_prp() >> 16;
			input_reg_buf[18] = diag_get_all_prp() & 0xffff;
			input_reg_buf[19] = diag_get_all_alarm() >> 16;
			input_reg_buf[20] = diag_get_all_alarm();
			for(i = 0;i < 10; ++ i)
			{
				input_reg_buf[21 + i] = param_get_data(PAR_ID_SN_CODE + i);
			}
			input_reg_buf[31] = var_get_data(VAR_ID_SOP_CV);
			input_reg_buf[32] = var_get_data(VAR_ID_SOP_CC);
			input_reg_buf[33] = var_get_data(VAR_ID_SOP_DV);
			input_reg_buf[34] = var_get_data(VAR_ID_SOP_DC);
			if(var_get_data(VAR_ID_BUS_CURR) == 30000)
			{
				input_reg_buf[35] = 0xffff;
				input_reg_buf[36] = 0xffff;
			}
			else
			{
				if(var_get_data(VAR_ID_BUS_CURR) > 0)
				{
					input_reg_buf[35] = (param_get_data(PAR_ID_FULL_CAP) - var_get_data(VAR_ID_DISP_RCAP)) * 60 / (var_get_data(VAR_ID_BUS_CURR) - 30000);
					input_reg_buf[36] = 0xffff;
				}
				else
				{
					input_reg_buf[35] = 0xffff;
					input_reg_buf[36] = var_get_data(VAR_ID_DISP_RCAP) * 60 / (30000 - var_get_data(VAR_ID_BUS_CURR));
				}
			}
			
			input_reg_buf[37] = 0x01;
			input_reg_buf[38] = 0x01;
			input_reg_buf[39] = param_get_data(PAR_ID_CYCLE);
			input_reg_buf[40] = 0;
			input_reg_buf[41] = param_get_data(PAR_ID_CB_CELL_NUM);;
			for(i = 0;i < 16; ++ i)
			{
				input_reg_buf[42 + i] = var_get_data(VAR_ID_CELL_VOLT01 + i);
			}
			input_reg_buf[58] = param_get_data(PAR_ID_CB_TEMP_NUM);	
			for(i = 0;i < CFG_TEMP_NUM; ++ i)
			{
				input_reg_buf[59 + i] = var_get_data(VAR_ID_CELL_TEMP01 + i);
			}
			
			return TRUE;
		}
		else
		{
			return FALSE;
		}
	}
}

static uint8_t jbd_modbus_update_input2_buf(md_data_type md_data_msg)
{
	uint8_t i = 0;
	uint8_t addr = 0;
	addr = md_data_msg.addr - 0x10;
	uint8_t hard_name[16] = HARD_PLATFORM;
	uint8_t prj_name[16] = PRJ_NAME;
	
	/* 统计信息 */
	if((0 == addr) || (1 == addr))
	{
		input2_reg_buf[0] = boot_param_read_par(BP_ID_BOOT_VER);
		input2_reg_buf[1] = var_get_data(VAR_ID_HARD_VER);
		input2_reg_buf[2] = SOFT_VER_MAIN;
		input2_reg_buf[3] = SOFT_VER_RELEASE;
		input2_reg_buf[4] = SOFT_VER_TEST;
		input2_reg_buf[5] = PROTOCOL_VER;
		for(i = 0;i < 8; ++ i)
		{
			input2_reg_buf[6 + i] = (hard_name[i * 2 + 1] << 8) + hard_name[i * 2];
		}
	
		for(i = 0;i < 8; ++ i)
		{
			input2_reg_buf[14 + i] = (prj_name[i * 2 +1] << 8) + prj_name[i * 2];
		}
	}
	else
	{
		addr = addr - 1;
		if((master_data_reg.com_err_state & (1 << addr)) && (addr < CFG_PARALLEL_NUM))
		{
			input2_reg_buf[0] = boot_param_read_par(BP_ID_BOOT_VER);
			input2_reg_buf[1] = var_get_data(VAR_ID_HARD_VER);
			input2_reg_buf[2] = SOFT_VER_MAIN;
			input2_reg_buf[3] = master_data_reg.slave_data[addr].version;
			input2_reg_buf[4] = master_data_reg.slave_data[addr].ver_test;
			input2_reg_buf[5] = PROTOCOL_VER;
			for(i = 0;i < 8; ++ i)
			{
				input2_reg_buf[6 + i] = (hard_name[i * 2 + 1] << 8) + hard_name[i * 2];
			}
		
			for(i = 0;i < 8; ++ i)
			{
				input2_reg_buf[14 + i] = (prj_name[i * 2 +1] << 8) + prj_name[i * 2];
			
			}
			
			return TRUE;
		}
		else
		{
			return FALSE;
		}
	}
}


static void jbd_modbus_read_hold1_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len)
{
	uint16_t data_len = 0;
    uint16_t crc_code = 0;
    uint8_t i = 0;
    uint8_t *p_tx = tx_buf;
    uint16_t start_addr = 0;

    *p_tx ++ = md_data_msg.addr;
    *p_tx ++ = md_data_msg.cmd_code;
    data_len = md_data_msg.data_len * 2; 
    *p_tx ++ = data_len; 
   	
    start_addr = md_data_msg.reg_addr - HOLD1_REG_ST;
    for(i = 0;(i < md_data_msg.data_len) && (i < HOLD1_REG_SIZE); ++ i)
    {
        *p_tx ++ = hold1_reg_buf[i + start_addr] >> 8;
        *p_tx ++  = hold1_reg_buf[i + start_addr] & 0xff;
    }
	
    crc_code = modbus_calc_crc(tx_buf , data_len + 3);

    *p_tx ++ = crc_code;
    *p_tx ++ = crc_code >> 8;

    *tx_len = (data_len + 5);
}

static void jbd_modbus_read_hold2_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len)
{
	uint16_t data_len = 0;
    uint16_t crc_code = 0;
    uint8_t i = 0;
    uint8_t *p_tx = tx_buf;
    uint16_t start_addr = 0;

    *p_tx ++ = md_data_msg.addr;
    *p_tx ++ = md_data_msg.cmd_code;
    data_len = md_data_msg.data_len * 2; 
    *p_tx ++ = data_len; 
   	
    start_addr = md_data_msg.reg_addr - HOLD2_REG_ST;
    for(i = 0;(i < md_data_msg.data_len) && (i < HOLD2_REG_SIZE); ++ i)
    {
        *p_tx ++ = hold2_reg_buf[i + start_addr] >> 8;
        *p_tx ++  = hold2_reg_buf[i + start_addr] & 0xff;
    }
	
    crc_code = modbus_calc_crc(tx_buf , data_len + 3);

    *p_tx ++ = crc_code;
    *p_tx ++ = crc_code >> 8;

    *tx_len = (data_len + 5);
}

static void jbd_modbus_write_hold1_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len)
{
	uint8_t i = 0;
	uint16_t start_addr = md_data_msg.reg_addr - HOLD1_REG_ST;
	for(i = 0 ;i < md_data_msg.data_len; ++ i)
	{
		if(i + start_addr >= SYS_PRP_PARA_NUM)
			break;
		
		param_set_data(sys_para_map_list[i + start_addr] , md_data_msg.data_buf[i]);
	}
}

static void jbd_modbus_write_hold2_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len)
{
	uint8_t i = 0;
	uint8_t rtc_flag = 0;
	uint16_t start_addr = md_data_msg.reg_addr - HOLD2_REG_ST;
	rtc_data_type rtc_time = {0};
	for(i = 0 ;i < md_data_msg.data_len; ++ i)
	{
		switch(i + start_addr)
		{
			case 0:
				rtc_time.year = md_data_msg.data_buf[i];
				rtc_flag = 1;
				break;
			case 1:
				rtc_time.month = md_data_msg.data_buf[i] >> 8;
				rtc_time.day = md_data_msg.data_buf[i];
				rtc_flag = 1;
				break;
			case 2:
				rtc_time.hour = md_data_msg.data_buf[i] >> 8;
				rtc_time.min = md_data_msg.data_buf[i];
				rtc_flag = 1;
				break;
			case 3:
				rtc_time.sec = md_data_msg.data_buf[i] >> 8;
				rtc_time.week = md_data_msg.data_buf[i];
				rtc_flag = 1;
				break;
			case 4:
				if((md_data_msg.data_buf[i] & 0xfffc) == 0xA500)
				{
					var_set_data(VAR_ID_MOS_LOCK , (md_data_msg.data_buf[i] & 0x00ff) | 0xAA00);
				}
				break;
			case 5:
				param_set_data(PAR_ID_PCS_RS485_TYPE , md_data_msg.data_buf[i]);
				break;
			case 6:
				param_set_data(PAR_ID_PCS_CAN_TYPE , md_data_msg.data_buf[i]);
				break;
			case 7:
				param_set_data(PAR_ID_RS485_RATE , md_data_msg.data_buf[i]);
				break;
			case 8:
				param_set_data(PAR_ID_CAN_RATE , md_data_msg.data_buf[i]);
				break;
			case 9:
				param_set_data(PAR_ID_SOP_CV , md_data_msg.data_buf[i]);
				break;
			case 10:
				param_set_data(PAR_ID_SOP_CC , md_data_msg.data_buf[i]);
				break;
			case 11:
				param_set_data(PAR_ID_SOP_DV , md_data_msg.data_buf[i]);
				break;
			case 12:
				param_set_data(PAR_ID_SOP_DC , md_data_msg.data_buf[i]);
				break;
			case 13:
				param_set_data(PAR_ID_BLC_MODE , md_data_msg.data_buf[i]);
				break;
			case 14:
				var_set_data(VAR_ID_REMOTE_CMD , md_data_msg.data_buf[i]);
				break;
			default:
				break;
		}
	}
	
	if(1 == rtc_flag)
	{
		If_rtc_set_time(rtc_time);
	}
}

static void jbd_modbus_write_reply_reg(md_data_type md_data_msg , uint8_t *tx_buf ,uint16_t *tx_len)
{
	uint16_t data_len = 0;
    uint16_t crc_code = 0;
    uint8_t *p_tx = tx_buf;
	
    *p_tx ++ = md_data_msg.addr;
    *p_tx ++ = md_data_msg.cmd_code;
	*p_tx ++ = md_data_msg.reg_addr >> 8;
	*p_tx ++ = md_data_msg.reg_addr & 0xff;
    *p_tx ++ = md_data_msg.data_len >> 8; 
    *p_tx ++ = md_data_msg.data_len & 0xff; 

    crc_code = modbus_calc_crc(tx_buf , 6);

    *p_tx ++ = crc_code;
    *p_tx ++ = crc_code >> 8;

    *tx_len = (data_len + 8);
}

static void jbd_modbus_update_hold2_buf(void)
{
	rtc_data_type rtc_time = {0};
	
	If_rtc_read_time(&rtc_time);
	
    hold2_reg_buf[0] = rtc_time.year;
	hold2_reg_buf[1] = (rtc_time.month << 8) + rtc_time.day;
	hold2_reg_buf[2] = (rtc_time.hour << 8) + rtc_time.min;
	hold2_reg_buf[3] = (rtc_time.sec << 8) + rtc_time.week;
	
	hold2_reg_buf[4] = var_get_data(VAR_ID_MOS_LOCK);
	hold2_reg_buf[5] = param_get_data(PAR_ID_PCS_RS485_TYPE);
	hold2_reg_buf[6] = param_get_data(PAR_ID_PCS_CAN_TYPE);
	hold2_reg_buf[7] = param_get_data(PAR_ID_RS485_RATE);
	hold2_reg_buf[8] = param_get_data(PAR_ID_CAN_RATE);

	hold2_reg_buf[9] = param_get_data(PAR_ID_SOP_CV);
	hold2_reg_buf[10] = param_get_data(PAR_ID_SOP_CC);
	hold2_reg_buf[11] = param_get_data(PAR_ID_SOP_DV);
	hold2_reg_buf[12] = param_get_data(PAR_ID_SOP_DC);
	hold2_reg_buf[13] = param_get_data(PAR_ID_BLC_MODE);

	hold2_reg_buf[14] = var_get_data(VAR_ID_REMOTE_CMD);
}

static void jbd_modbus_update_hold1_buf(void)
{
	uint8_t i = 0;
	
	for(i = 0 ;i < SYS_PRP_PARA_NUM; ++ i)
	{
		hold1_reg_buf[i] = param_get_data(sys_para_map_list[i]);
	}
}

static uint32_t get_salve_prp_msg(uint8_t slave_addr)
{
	diag_prp_type diag_prp_msg = {0};
	
	diag_prp_msg.bit.cov = master_data_reg.slave_data[slave_addr].prp_volt_status.name.cov;
	diag_prp_msg.bit.cuv = master_data_reg.slave_data[slave_addr].prp_volt_status.name.cuv;
	diag_prp_msg.bit.bov = master_data_reg.slave_data[slave_addr].prp_volt_status.name.bov;
	diag_prp_msg.bit.buv = master_data_reg.slave_data[slave_addr].prp_volt_status.name.buv;
	
	diag_prp_msg.bit.occ = master_data_reg.slave_data[slave_addr].prp_volt_status.name.occ;
	diag_prp_msg.bit.ocd = master_data_reg.slave_data[slave_addr].prp_volt_status.name.ocd;
	diag_prp_msg.bit.ocd2 = master_data_reg.slave_data[slave_addr].prp_volt_status.name.ocd2;
	diag_prp_msg.bit.sc = master_data_reg.slave_data[slave_addr].prp_volt_status.name.sc;
	diag_prp_msg.bit.col = master_data_reg.slave_data[slave_addr].prp_volt_status.name.col;
	diag_prp_msg.bit.afe_err = master_data_reg.slave_data[slave_addr].prp_volt_status.name.afe_err;
	diag_prp_msg.bit.vdiff = master_data_reg.slave_data[slave_addr].prp_volt_status.name.vdiff;
	
	diag_prp_msg.bit.otc = master_data_reg.slave_data[slave_addr].prp_temp_status.name.otc;
	diag_prp_msg.bit.otd = master_data_reg.slave_data[slave_addr].prp_temp_status.name.otd;
	diag_prp_msg.bit.utc = master_data_reg.slave_data[slave_addr].prp_temp_status.name.utc;
	diag_prp_msg.bit.utd = master_data_reg.slave_data[slave_addr].prp_temp_status.name.utd;
	diag_prp_msg.bit.otm = master_data_reg.slave_data[slave_addr].prp_temp_status.name.otm;
	diag_prp_msg.bit.ute = master_data_reg.slave_data[slave_addr].prp_temp_status.name.ute;
	diag_prp_msg.bit.ote = master_data_reg.slave_data[slave_addr].prp_temp_status.name.ote;
	diag_prp_msg.bit.fcmos = master_data_reg.slave_data[slave_addr].prp_temp_status.name.cmos_ft;
	diag_prp_msg.bit.fdmos = master_data_reg.slave_data[slave_addr].prp_temp_status.name.dmos_ft;
	diag_prp_msg.bit.tol = master_data_reg.slave_data[slave_addr].prp_temp_status.name.tol;
	
	return diag_prp_msg.prp_word;
}

static uint32_t get_salve_alm_msg(uint8_t slave_addr)
{
	uint16_t alm_msg = 0;
	diag_alm_type diag_alm_msg = {0};
	
	alm_msg = master_data_reg.slave_data[slave_addr].alarm_status;
	if(alm_msg & (1 << 0))
		diag_alm_msg.bit.cov = 1;
	if(alm_msg & (1 << 1))
		diag_alm_msg.bit.cuv = 1;
	if(alm_msg & (1 << 2))
		diag_alm_msg.bit.ocd = 1;
	if(alm_msg & (1 << 3))
		diag_alm_msg.bit.occ = 1;
	if(alm_msg & (1 << 4))
		diag_alm_msg.bit.bov = 1;
	if(alm_msg & (1 << 5))
		diag_alm_msg.bit.buv = 1;
	if(alm_msg & (1 << 6))
		diag_alm_msg.bit.otc = 1;
	if(alm_msg & (1 << 7))
		diag_alm_msg.bit.utc = 1;
	if(alm_msg & (1 << 8))
		diag_alm_msg.bit.otd = 1;
	if(alm_msg & (1 << 9))
		diag_alm_msg.bit.utd = 1;
	if(alm_msg & (1 << 10))
		diag_alm_msg.bit.omtd = 1;
	if(alm_msg & (1 << 11))
		diag_alm_msg.bit.socl = 1;
	if(alm_msg & (1 << 12))
		diag_alm_msg.bit.oetd = 1;
	if(alm_msg & (1 << 13))
		diag_alm_msg.bit.uetd = 1;
	if(alm_msg & (1 << 14))
		diag_alm_msg.bit.vdiff = 1;
	if(alm_msg & (1 << 15))
		diag_alm_msg.bit.full_chg = 1;		

	return diag_alm_msg.alm_word;
}

static uint16_t get_master_sys_status(void)
{
	uint16_t sys_status = 0;
	
	if(master_data_reg.fet_status & 0x01)
		sys_status |= (1 << 0);
	if(master_data_reg.fet_status & 0x02)
		sys_status |= (1 << 1);
	if(master_data_reg.total_bus_curr > 0)
		sys_status |= (1 << 2);
	else if(master_data_reg.total_bus_curr < 0)
		sys_status |= (1 << 3);
	else
	{
		;
	}
	
	return sys_status;
}

static uint16_t get_slave_sys_status(uint8_t slave_addr)
{
	uint16_t sys_status = 0;
	
	if(master_data_reg.slave_data[slave_addr].fet_status & (1 << 0))
		sys_status |= (1 << 0);
	if(master_data_reg.slave_data[slave_addr].fet_status & (1 << 1))
		sys_status |= (1 << 1);
	if(master_data_reg.slave_data[slave_addr].fet_status & (1 << 3))
		sys_status |= (1 << 2);
	if(master_data_reg.slave_data[slave_addr].fet_status & (1 << 2))
		sys_status |= (1 << 3);
	if(master_data_reg.slave_data[slave_addr].fet_status & (1 << 4))
		sys_status |= (1 << 4);
	if(master_data_reg.slave_data[slave_addr].fet_status & (1 << 5))
		sys_status |= (1 << 5);
	if(master_data_reg.slave_data[slave_addr].fet_status & (1 << 6))
		sys_status |= (1 << 6);
	else
	{
		;
	}
	
	return sys_status;
}

static uint16_t get_self_sys_status(void)
{
	uint16_t sys_status = 0;
	uint8_t read_data = 0;

    read_data = var_get_data(VAR_ID_MOS_STATE);
    if(read_data & (1 << VAR_MOS_ST_DSG))
        sys_status |= (1 << 0);
    if(read_data & (1 << VAR_MOS_ST_CHG))
        sys_status |= (1 << 1);
    read_data = var_get_data(VAR_ID_CURR_DR);
    if(read_data == CURR_DR_DSG)
        sys_status |= (1 << 3);
    else if(read_data == CURR_DR_CHG)
        sys_status |= (1 << 2);
	else
	{
		;
	}
	
	if(If_do_get_out_state(DO_LIMIT_10A) == DO_OUT_ON)
		sys_status |= (1 << 4);
	if(If_do_get_out_state(DO_RLY_FAULT) == DO_OUT_ON)
		sys_status |= (1 << 5);
	if(If_do_get_out_state(DO_RLY_SOCL) == DO_OUT_ON)
		sys_status |= (1 << 6);
    else
	{
		;
	}
		
	return sys_status;
}
/********** Copyright (c) 2023 JBD-Energy Storage Technology Co. LTD *********/
